<?php 
use \Hprose\Future ;
use \Workerman\Worker;
use \Workerman\Events\EventInterface;

class Proc
{  
    public static $debug = false;
    /**
     * 僵尸进程 
     */
    public static function fork($fn,$args=[])
    {   
        if(self::$debug){
            //$fn = unserialize(serialize(new \Opis\Closure\SerializableClosure($fn)));
            \Hprose\Future\co(function()use($fn,$args){
                try{
                    yield $fn($args);
                }catch(\Throwable $e){
                    echo $e; 
                } 
            });
            return;
        } 
        static $include;
        if (empty($include)) {
            foreach (get_declared_classes() as $composer) {
                if (substr($composer, 0, 22)=='ComposerAutoloaderInit') {
                    $ref = new \ReflectionClass($composer);
                    $file = $ref->getFileName();
                    $class = xlx\OTPWorker::class;
                    $include = "require_once '$file';$composer::getLoader();";
                }
            }
        }
        if (empty($include)) {
            throw new Exception("Error Processing Request", 1);
        }
        if(\is_array($fn)){
            $fn = \var_export($fn,true); 
        }else{
            $fn = 'unserialize(base64_decode(\''.base64_encode(serialize(new \Opis\Closure\SerializableClosure($fn)) ). '\'))';
        }
        $string = '\Hprose\Future\co('.$fn.','.preg_replace("/[\r\n]+/",'',var_export($args,true)).');';
              //  .'->then(null, function ($e) { echo $e; /* \xlx\Process::exit(); */    });';     
        if (strpos(strtolower(PHP_OS), 'win') === 0) {
            popen($c = 'start /B '.\PHP_BINARY.' -r "'.$include
                ."class_alias(\xlx\Windows\Events\Select::class, \Workerman\Events\Select::class);" 
                .' /*window select*/ '.$string, 'w' ); 
        } else { 
            popen(\PHP_BINARY.' -r "eval(base64_decode(\''.base64_encode($include.$string).'\'));" &>/dev/null ','w');
        }
    }


 
    public static function startEventLoop()
    { 
        if (empty(\Workerman\Worker::$globalEvent)) { 
            $method = new \ReflectionMethod(Worker::class, 'getEventLoopName');
            $method->setAccessible(true);
            $CLASS = $method->invoke(null);
            $GLOBALS['_']=new class{
                function __destruct(){
                    Worker::$globalEvent->loop();
                }
            }; 
            Worker::$globalEvent = new $CLASS; 
        }  
        return Worker::$globalEvent;
    }
    public static function checkAddr($addr){
        preg_match('/([\d\.]+):(\d+)/',$addr,$arr);
        if($arr[2] > 65536){
            throw new \Exception("Error Port Number", 1); 
        } 
        $addr = "{$arr[1]}:{$arr[2]}";
        if (strpos(strtolower(PHP_OS), 'win') === 0) {
            return !!\system("netstat -ano|findstr $addr");
        } else {
            //ubuntu bash on windows10 not support
            return !!\system("netstat -anp|grep $addr"); 
        }
    }


    // public static function delay($time){ 
    //     $defer = new Future();  
    //     $gen = \Proc::getContext(); 
        
    //     $event = Worker::$globalEvent;
    //     $event->add($time,EventInterface::EV_TIMER_ONCE,function()use($defer ){ 
    //         //if(empty($gen->exit)){
    //             $defer->resolve(); 
    //         //}
    //     });


    //     return $defer;
    // }

    public static $defers;
    public static function yield(/*===self::delay(0);*/){ 
        $defer = new Future(); 
        // $event = Worker::$globalEvent;
        // $event->add(0.0001,EventInterface::EV_TIMER_ONCE,function()use($defer){  
        //     $defer->resolve(); 
        // });
        // return $defer;
        if(empty(self::$defers)){
            self::$defers[] = $defer;
            $event = Worker::$globalEvent;
            //Workerman 最小时钟间隔 不支持0间隔
            $event->add(0.0001,EventInterface::EV_TIMER_ONCE,function(){ 
                $arr = self::$defers;
                self::$defers = null;
                foreach ($arr as $defer) {
                    $defer->resolve();
                }
            }); 
            return $defer; 
        } 
        return self::$defers[] = $defer; 
    }

    public static function getContext( ){
        $stack_list = debug_backtrace();
        for ($i=0; $i < count($stack_list); $i++) {
            $stack = $stack_list[$i];
            if (isset($stack['object']) && $stack['object'] instanceof Generator) {
                return $stack['object'];
            }
        }
        throw new Exception("Error Processing Request", 1);

    }

} 